﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Configuration;
using System.Reflection;
using n = EnnErrE.Utils.Numbers;

namespace EnnErrE.BillFiller
{
    /// <summary>
    /// Gestione della compilazione di un bollettino.
    /// </summary>
    public class BillCompiler
    {
        /// <summary>
        /// Imposta/Restituisce le impostazioni del bollettino da compilare.
        /// </summary>
        public BillSettings Settings { get; set; }
        /// <summary>
        /// Imposta/Restituisce i dati con i quali compilare il bollettino.
        /// </summary>
        public BillData Data { get; set; }
        /// <summary>
        /// Risoluzione orizzontale dell'immagine del bollettino compilato.
        /// </summary>
        /// <remarks>Il valore di default è 100.</remarks>
        public int DpiX { get; set; }
        /// <summary>
        /// Risoluzione verticale dell'immagine del bollettino compilato.
        /// </summary>
        /// <remarks>Il valore di default è 100.</remarks>
        public int DpiY { get; set; }
        /// <summary>
        /// Costruttore.
        /// </summary>
        /// <param name="data">Dati con i quali compilare un bollettino.</param>
        /// <remarks>Le impostazioni del bollettino sono quelle standard di un bollettino, come definito dal costruttore di default della classe <see cref="EnnErrE.BillSettings">BillSettings</see>.</remarks>
        public BillCompiler(BillData data) : this(new BillSettings(), data) { }
        /// <summary>
        /// Costruttore.
        /// </summary>
        /// <param name="settings">Impostazioni del bollettino.</param>
        /// <param name="data">Dati con i quali compilare un bollettino.</param>
        public BillCompiler(BillSettings settings, BillData data)
        {
            Settings = settings;
            Data = data;
            DpiX = 100;
            DpiY = 100;
        }

        /// <summary>
        /// Disegna una stringa lettera per lettera in box.
        /// </summary>
        /// <param name="graphics">Dispositivo grafico su cui disegnare.</param>
        /// <param name="text">Testo da disegnare.</param>
        /// <param name="f">Font da utilizzare per il disegno.</param>
        /// <param name="place">Dimensioni di un singolo box.</param>
        /// <param name="spacing">Spaziatura tra i box.</param>
        private void DrawBoxedText(Graphics graphics, string text, Font f, RectangleF place, float spacing)
        {
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            text = text.ToUpper();
            for (int index = 0; index < text.Length; ++index)
            {
                graphics.DrawString(text[index].ToString(), f, Brushes.Black, place, sf);
                place.Offset(place.Width + spacing, 0);
            }
        }
        /// <summary>
        /// Disegna una stringa lettera per lettera in box.
        /// </summary>
        /// <param name="graphics">Dispositivo grafico su cui disegnare.</param>
        /// <param name="text">Testo da disegnare.</param>
        /// <param name="f">Font da utilizzare per il disegno.</param>
        /// <param name="place">Dimensioni di un singolo box.</param>
        /// <param name="spacing">Spaziatura tra i box.</param>
        /// <param name="len">Lunghezza della stringa.</param>
        private void DrawBoxedText(Graphics g, string text, int len, Font f, RectangleF place, float spacing)
        {
            if (text.Length > len)
                text = text.Substring(0, len);
            else
                text = text.PadLeft(len, ' ');
            DrawBoxedText(g, text, f, place, spacing);
        }
        /// <summary>
        /// Restituisce il bollettino compilato.
        /// </summary>
        /// <returns>L'immagine grafica del bollettino compilato.</returns>
        public Image GetCompiledBill()
        {
            // le dimensioni del bollettino sono espresse in pollici, quelle dell'immagine in pixels.
            int width = Settings.BillSize.Width * DpiX;
            int height = Settings.BillSize.Height * DpiY;
            Bitmap result = new Bitmap(Settings.BillSize.Width, Settings.BillSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            result.SetResolution(DpiX, DpiY);
            Graphics graphics = Graphics.FromImage(result);
            graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
            Font f = new System.Drawing.Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
            StringFormat sf = new StringFormat();
            foreach (BillField item in Settings.Fields)
            {
                string text = string.Empty;
                MemberInfo[] mi = typeof(BillData).GetMember(item.Content, MemberTypes.Property, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                if (mi.Length > 0)
                    text = typeof(BillData).InvokeMember(mi[0].Name, BindingFlags.GetProperty, Type.DefaultBinder, Data, null).ToString();
                else
                    text = item.Content;

                if (text.Length > 0)
                    item.Compile(graphics, f, text);
            }
            return result;
        }
    }
}
